package com.miplus.ccrm.core.service.conf;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.miplus.ccrm.common.CmdResVo;
import com.miplus.ccrm.common.EnumRCode;
import com.miplus.ccrm.common.JPubUtils;
import com.miplus.ccrm.common.ServiceException;
import com.miplus.ccrm.core.controller.vo.LabelResVo;
import com.miplus.ccrm.core.controller.vo.conf.*;
import com.miplus.ccrm.core.pojo.*;
import com.miplus.ccrm.core.mapper.MsgDefineMapper;
import com.miplus.ccrm.core.service.strategy.CfgRuleConditionsService;
import com.miplus.ccrm.core.service.strategy.CfgRuleVarsService;
import com.miplus.ccrm.core.utils.EnumRuleVarsOp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author pc
* @description 针对表【msg_define】的数据库操作Service实现
* @createDate 2024-03-08 10:00:20
*/
@Service
@Slf4j
public class MsgDefineServiceImpl extends MPJBaseServiceImpl<MsgDefineMapper, MsgDefine>
    implements MsgDefineService{

    @Resource
    MsgDefinePlanService msgDefinePlanService;

    @Resource
    MsgDefineFieldService msgDefineFieldService;

    @Resource
    CfgRuleVarsService cfgRuleVarsService;

    @Resource
    CfgRuleConditionsService cfgRuleConditionsService;

    @Override
    public IPage<MsgTmpResVo> msgTempList(MsgTmpReqVo paras)
    {
        return selectJoinListPage(new Page<>(paras.getPageNum(), paras.getPageSize()),
                MsgTmpResVo.class,
                new MPJLambdaWrapper<MsgDefine>()
                        .selectAs("fun_getnames('PUBLIC.MORAUTO',t.sendmode)",MsgTmpResVo::getSendmodename)
                        .selectAll(MsgDefine.class)
                        .like(JPubUtils.IsNotEmpty(paras.getName()),"name",paras.getName())
                        .eq(JPubUtils.IsNotEmpty(paras.getStatus()),"status",paras.getStatus())
                        .eq(JPubUtils.IsNotEmpty(paras.getId()),"msgid",paras.getId())
                        .eq(JPubUtils.IsNotEmpty(paras.getChannel()),MsgDefine::getChannel,paras.getChannel())
        ).convert(x-> {
            x.setPlanTime(new ArrayList<>());
            List<MsgDefinePlan> msgdefineplans = msgDefinePlanService.getBaseMapper().selectList(
                    new LambdaQueryWrapper<MsgDefinePlan>()
                            .eq(MsgDefinePlan::getOriginalid, x.getId())

            );
            if (msgdefineplans != null && msgdefineplans.size() > 0) {
                for (MsgDefinePlan p : msgdefineplans) {
                    MsgDefinePlanVo mv = new MsgDefinePlanVo();
                    mv.setStarttime(p.getStarttime());
                    mv.setEndtime(p.getEndtime());
                    x.getPlanTime().add(mv);
                }

            }
            //AI channel
            if (x.getChannel() == 2) {
              x.setMsgDefineFieldList( msgDefineFieldService.getBaseMapper().selectList(
                        new LambdaQueryWrapper<MsgDefineField>()
                                .eq(MsgDefineField::getMsgid, x.getId())
                                .orderByAsc(MsgDefineField::getSeqnum)
                ).stream().map(msgDefineField -> {
                    MsgDefineFieldVo msgDefineFieldVo = new MsgDefineFieldVo();
                    BeanUtils.copyProperties(msgDefineField, msgDefineFieldVo);
                    return msgDefineFieldVo;
                }).collect(Collectors.toList()));
            }
            x.setCfgRuleConditionsList(getRuleConditionList(x.getId()));
            return x;
        });

    }

    @Override
    public CmdResVo updateMsgTmp(String usrid, MsgTmpEditReqVo paras)
    {
        if(StringUtils.isEmpty(paras.getId()))
            return new CmdResVo(-1,"参数错误");
        MsgDefine def=getById(paras.getId());
        if(def == null)
            return new CmdResVo(-1,"模板不存在");
        //BeanUtils.copyProperties(paras,def);
        //int ret= baseMapper.updateById(def);
        insertRuleStepConditions(usrid, paras.getId(),paras.getCfgRuleConditionsList());
        //根据条件自动拼接SQL语句
        //def.setContentsql(getStepConditionSql(def.getId(), def.getTargetsql()));
        //updateById(def);
        int ret=baseMapper.update(def,new LambdaUpdateWrapper<MsgDefine>()
                .eq(MsgDefine::getId,paras.getId())
                .set(MsgDefine::getName,paras.getName())
                .set(MsgDefine::getAlertsql,paras.getAlertsql())
                .set(MsgDefine::getDepts,paras.getDepts())
                .set(MsgDefine::getDisttags,paras.getDisttags())
                .set(MsgDefine::getDsc,paras.getDsc())
                .set(MsgDefine::getMsgtype,paras.getMsgtype())
                .set(MsgDefine::getOverdueday1,paras.getOverdueday1())
                .set(MsgDefine::getOverdueday2,paras.getOverdueday2())
                .set(MsgDefine::getProductids,paras.getProductids())
                .set(MsgDefine::getRelationids,paras.getRelationids())
                .set(MsgDefine::getRoleids,paras.getRoleids())
                .set(MsgDefine::getSendmode,paras.getSendmode())
                .set(MsgDefine::getSms,paras.getSms())
                .set(MsgDefine::getSmstxt,paras.getSmstxt())
                .set(MsgDefine::getStatus,paras.getStatus())
                .set(MsgDefine::getTargetmode,paras.getTargetmode())
                .set(MsgDefine::getTitle,paras.getTitle())
                .set(MsgDefine::getTargetsql,paras.getTargetsql())
                .set(MsgDefine::getContentsql,getStepConditionSql( paras.getId(), paras.getContentsql()))
                .set(MsgDefine::getUrl,paras.getUrl())
                .set(MsgDefine::getWechat,paras.getWechat())
                .set(MsgDefine::getWxtxt,paras.getWxtxt())
                .set(MsgDefine::getMddt,new Date())
                .set(MsgDefine::getMdusr,usrid)
        );
        insertPlanTime(paras.getId(), paras.getPlanTime());
        if(def.getChannel() == 2){
            insertMsgField(paras.getId(),paras.getMsgDefineFieldList());
        }

        return new CmdResVo(ret);
    }


    @Override
    public CmdResVo addMsgTmp(String usrid, MsgTmpEditReqVo paras)
    {
        if(StringUtils.isEmpty(paras.getId()))
            return new CmdResVo(-1,"参数错误");
        MsgDefine def=getById(paras.getId());
        if(def == null)
            return insertMsgTmp(usrid, paras);
        //BeanUtils.copyProperties(paras,def);
        //int ret= baseMapper.updateById(def);
        insertRuleStepConditions(usrid, paras.getId(),paras.getCfgRuleConditionsList());
        //根据条件自动拼接SQL语句
        //def.setContentsql(getStepConditionSql(def.getId(), def.getTargetsql()));
        //updateById(def);
        int ret=baseMapper.update(def,new LambdaUpdateWrapper<MsgDefine>()
                .eq(MsgDefine::getId,paras.getId())
                .set(MsgDefine::getName,paras.getName())
                .set(MsgDefine::getAlertsql,paras.getAlertsql())
                .set(MsgDefine::getDepts,paras.getDepts())
                .set(MsgDefine::getDisttags,paras.getDisttags())
                .set(MsgDefine::getDsc,paras.getDsc())
                .set(MsgDefine::getMsgtype,paras.getMsgtype())
                .set(MsgDefine::getOverdueday1,paras.getOverdueday1())
                .set(MsgDefine::getOverdueday2,paras.getOverdueday2())
                .set(MsgDefine::getProductids,paras.getProductids())
                .set(MsgDefine::getRelationids,paras.getRelationids())
                .set(MsgDefine::getRoleids,paras.getRoleids())
                .set(MsgDefine::getSendmode,paras.getSendmode())
                .set(MsgDefine::getSms,paras.getSms())
                .set(MsgDefine::getSmstxt,paras.getSmstxt())
                .set(MsgDefine::getStatus,paras.getStatus())
                .set(MsgDefine::getTargetmode,paras.getTargetmode())
                .set(MsgDefine::getTitle,paras.getTitle())
                .set(MsgDefine::getTargetsql,paras.getTargetsql())
                .set(MsgDefine::getContentsql,getStepConditionSql( paras.getId(), paras.getTargetsql()))
                .set(MsgDefine::getUrl,paras.getUrl())
                .set(MsgDefine::getWechat,paras.getWechat())
                .set(MsgDefine::getWxtxt,paras.getWxtxt())
                .set(MsgDefine::getMddt,new Date())
                .set(MsgDefine::getMdusr,usrid)
        );
        insertPlanTime(paras.getId(), paras.getPlanTime());
        if(def.getChannel() == 2){
            insertMsgField(paras.getId(),paras.getMsgDefineFieldList());
        }

        return new CmdResVo(ret);
    }

    /**
     * 更新短信发送的时间段。先删除、后插入的方式。
     * @param msgId
     * @param msgDefinePlanVoList
     */
    private void insertPlanTime(String msgId, List<MsgDefinePlanVo> msgDefinePlanVoList)
    {
        // 删除 所有的时间设置：
        msgDefinePlanService.remove( new LambdaQueryWrapper<MsgDefinePlan>().eq(MsgDefinePlan::getOriginalid,msgId));
        List<MsgDefinePlan> definePlans = new ArrayList<>();
        if(msgDefinePlanVoList == null ||  msgDefinePlanVoList.size() == 0)
        {
            MsgDefinePlan mp = new MsgDefinePlan();
            mp.setOriginalid(msgId);
            mp.setStarttime("00:00:00");
            mp.setEndtime("23:59:59");
            definePlans.add(mp);
        }
        else{
            for( MsgDefinePlanVo v : msgDefinePlanVoList)
            {
                MsgDefinePlan mp = new MsgDefinePlan();
                mp.setOriginalid(msgId);
                mp.setStarttime(v.getStarttime());
                mp.setEndtime(v.getEndtime());
                definePlans.add(mp);
            }
        }
        msgDefinePlanService.saveBatch(definePlans);
    }
    private void insertMsgField(String msgId, List<MsgDefineFieldVo> msgDefineFieldList)
    {
        // 删除 所有的时间设置：
        msgDefineFieldService.remove( new LambdaQueryWrapper<MsgDefineField>().eq(MsgDefineField::getMsgid,msgId));
        if( msgDefineFieldList == null || msgDefineFieldList.size() == 0)
            return;
        List<Long> varIds = msgDefineFieldList.stream().map( x->{ return x.getVarId();}).collect(Collectors.toList());
        Map<Long,CfgRuleVars> cfgRuleVarsMap = cfgRuleVarsService.getBaseMapper().selectList(
            new LambdaQueryWrapper<CfgRuleVars>()
                    .in(CfgRuleVars::getVarId,varIds)
        ).stream().collect(Collectors.toMap(item -> item.getVarId(), item -> item));

        List<MsgDefineField> defineFields = new ArrayList<>();

       for( MsgDefineFieldVo v : msgDefineFieldList)
        {
            MsgDefineField mf = new MsgDefineField();
            CfgRuleVars vars = cfgRuleVarsMap.get(v.getVarId());
            mf.setMsgid(msgId);
            mf.setVarId(v.getVarId());
            mf.setVarName(v.getVarName());
            mf.setSeqnum(v.getSeqnum());

            mf.setFieldName(vars.getFieldName());
            mf.setTableName(vars.getTableName());
            mf.setTableAlias(vars.getTableAlias());
            String sql = String.format("%s%s.%s%s",
                    StringUtils.isNotEmpty(vars.getBeforeField())?vars.getBeforeField():"",
                    vars.getTableAlias(),
                    vars.getFieldName(),
                    StringUtils.isNotEmpty(vars.getAfterField())?vars.getAfterField():""
                    );
            mf.setFieldSql(sql);
            defineFields.add(mf);
        }
        msgDefineFieldService.saveBatch(defineFields);
    }

    @Override
    public CmdResVo insertMsgTmp(String usrid, MsgTmpEditReqVo paras) {
        MsgDefine msgDefine = baseMapper.selectById(paras.getId());
        if (msgDefine != null) {
            throw new ServiceException(EnumRCode.MsgDefineError.value, EnumRCode.MsgDefineError.name);
        }
        log.info("Insert msgdefine, msgId:<{}>, targetsql:<{}>",paras.getId(),paras.getTargetsql());
        MsgDefine def = new MsgDefine();
        BeanUtils.copyProperties(paras, def);
        if (JPubUtils.IsEmpty(paras.getChannel()))
        {
            def.setChannel(1); //缺省为短信模板。
        }
        def.setCrdt(new Date());
        def.setCrusr(usrid);
        int ret= baseMapper.insert(def);
        //增加时间安排。
        insertPlanTime(paras.getId(), paras.getPlanTime());
        if(def.getChannel() == 2){
            insertMsgField(paras.getId(),paras.getMsgDefineFieldList());
        }
        insertRuleStepConditions(usrid, paras.getId(),paras.getCfgRuleConditionsList());
        //根据条件自动拼接SQL语句
        def.setContentsql(getStepConditionSql(def.getId(), paras.getTargetsql()));
        updateById(def);

        return new CmdResVo(ret);
    }

    @Override
    public CmdResVo deleteMsgTmp(String id)
    {
        int ret= baseMapper.deleteById(id);
        msgDefinePlanService.remove( new LambdaQueryWrapper<MsgDefinePlan>().eq(MsgDefinePlan::getOriginalid,id));
        msgDefineFieldService.remove(new LambdaQueryWrapper<MsgDefineField>().eq(MsgDefineField::getMsgid,id));
        cfgRuleConditionsService.remove(new LambdaQueryWrapper<CfgRuleConditions>().eq(CfgRuleConditions::getMsgid,id));
        return new CmdResVo(ret);
    }

    @Override
    public CmdResVo updateStatus(String usrid, String id,String status)
    {
        MsgDefine def=new MsgDefine();
        def.setId(id);
        def.setStatus(status);
        def.setMddt(new Date());
        def.setMdusr(usrid);
        int ret = baseMapper.updateById(def);
        return new CmdResVo(ret);
    }

    @Override
    public List<LabelResVo> getMsgTmpList(String caseId,String contactnumber, String usrid,String sendmode,Integer channel,String msgid)
    {
        Integer msgChannel = 1;
        if(JPubUtils.IsNotEmpty(channel))
            msgChannel = channel;
        MPJLambdaWrapper<MsgDefine> wrapper = new MPJLambdaWrapper<MsgDefine>()
                .selectAs("msgid", LabelResVo::getValue)
                .selectAs("name", LabelResVo::getLabel)
                .select("msgid", "name")
                .eq("status", "1")
                .apply(String.format(" ifnull(channel,1) = %d ",msgChannel))
                .eq(JPubUtils.IsNotEmpty(sendmode), MsgDefine::getSendmode, sendmode);

//        if(StringUtils.isNotEmpty(usrid)) {
//            wrapper.exists(String.format("SELECT 1 FROM sys_urlink urlink WHERE urlink.usrid='%s' " +
//                    "and ifnull(FIND_IN_SET(urlink.roleid,t.roleids),1)>0", usrid));
//        }
        if(StringUtils.isNotEmpty(usrid) && sendmode.equals("2")) {
            wrapper.exists(String.format("SELECT 1 FROM sys_urlink urlink WHERE urlink.usrid='%s' and if(ifnull(t.roleids,''),FIND_IN_SET(urlink.roleid,t.roleids)>0,1)", usrid));
        }

        if(StringUtils.isNotEmpty(caseId)){
//            wrapper.exists(String.format("SELECT 1 FROM fi_creditcases fic " +
//                    " WHERE fic.creditcaseid='%s' and ifnull(FIND_IN_SET(fic.product_id, t.productids ),1)>0",caseId));
            wrapper.exists(String.format("SELECT pr.id FROM fi_creditcases fic LEFT JOIN iou_product pr ON pr.product_id=fic.product_id AND ifnull(pr.merchant_id,'') = ifnull(fic.merchant_id,'')WHERE fic.creditcaseid='%s' and if(ifnull(productids,''),FIND_IN_SET(pr.id,t.productids )>0,1)",caseId));
            wrapper.exists(String.format("SELECT 1 FROM fi_creditcases fic " +
                    " WHERE fic.creditcaseid ='%s' and ifnull(FIND_IN_SET(ifnull(fic.sendtodept,'-'), t.depts ),1)>0",caseId));
            wrapper.exists(String.format("SELECT 1 FROM fi_creditcases fic " +
                    " WHERE fic.creditcaseid='%s' and ifnull(fic.mths_day,0) >= ifnull(t.overdueday1,0) and " +
                    " ifnull(fic.mths_day,0) <= ifnull(t.overdueday2,9999999)",caseId));
            wrapper.exists(String.format("SELECT 1 FROM fi_creditcases fic " +
                    " WHERE fic.creditcaseid='%s' and ifnull(FIND_IN_SET(ifnull(fic.disttag,'-'), t.disttags ),1)>0",caseId));
        }
        if(StringUtils.isNotEmpty(contactnumber)){
            wrapper.exists(String.format("SELECT 1 FROM con_contact cc " +
                    " WHERE cc.contactnumber= %s and ifnull(FIND_IN_SET(ifnull(cc.relational,0), t.relationids ),1)>0",contactnumber));

        }
        //短信发送任务。
        if( msgChannel == 1 || StringUtils.isNotEmpty(caseId)) {
            wrapper.exists("select 1 from msg_define_plan mdp where mdp.originalid=t.msgid " +
                    " and date_format(now(),'%H:%i:%s') >= ifnull(mdp.starttime,'00:00:00') " +
                    " and date_format(now(),'%H:%i:%s') <= ifnull(mdp.endtime,'23:59:59') ");
        }

        if(msgid!=null){
            wrapper.eq("msgid",msgid);
        }

        return selectJoinList(
                LabelResVo.class,
                wrapper
        );
    }

    @Override
    public List<LabelResVo> getMsgTmpListAll(String sendmode,Integer channel) {

        Integer msgChannel = 1;
        if(JPubUtils.IsNotEmpty(channel))
            msgChannel = channel;
        MPJLambdaWrapper<MsgDefine> wrapper = new MPJLambdaWrapper<MsgDefine>()
                .selectAs("msgid", LabelResVo::getValue)
                .selectAs("name", LabelResVo::getLabel)
                .select("msgid", "name")
                .eq("status", "1")
                .apply(String.format(" ifnull(channel,1) = %d ",msgChannel))
                .eq(JPubUtils.IsNotEmpty(sendmode), MsgDefine::getSendmode, sendmode);
        return selectJoinList(
                LabelResVo.class,
                wrapper
        );
    }

    @Override
    public MsgTmpResVo getMsgTmpInfo(String tempID)
    {
        MsgTmpResVo msgTmpResVo = selectJoinOne(
                MsgTmpResVo.class,
                new MPJLambdaWrapper<MsgDefine>()
                        .selectAs("case when t.sendmode='1' then 'Y' else 'N' end",MsgTmpResVo::getSendmodename)
                        .selectAll(MsgDefine.class)
                        .eq(MsgDefine::getId,tempID)
        );
        if( msgTmpResVo != null){
            msgTmpResVo.setPlanTime(new ArrayList<>());
            List<MsgDefinePlan> msgdefineplans = msgDefinePlanService.getBaseMapper().selectList(
                    new LambdaQueryWrapper<MsgDefinePlan>()
                            .eq(MsgDefinePlan::getOriginalid,msgTmpResVo.getId())

            );
            if(msgdefineplans != null && msgdefineplans.size()>0)
            {
                for( MsgDefinePlan p :msgdefineplans )
                {
                    MsgDefinePlanVo mv = new MsgDefinePlanVo();
                    mv.setStarttime( p.getStarttime());
                    mv.setEndtime( p.getEndtime());
                    msgTmpResVo.getPlanTime().add(mv);
                }

            }
            if (msgTmpResVo.getChannel() == 2) {
                msgTmpResVo.setMsgDefineFieldList( msgDefineFieldService.getBaseMapper().selectList(
                        new LambdaQueryWrapper<MsgDefineField>()
                                .eq(MsgDefineField::getMsgid, msgTmpResVo.getId())
                                .orderByAsc(MsgDefineField::getSeqnum)
                ).stream().map(msgDefineField -> {
                    MsgDefineFieldVo msgDefineFieldVo = new MsgDefineFieldVo();
                    BeanUtils.copyProperties(msgDefineField, msgDefineFieldVo);
                    return msgDefineFieldVo;
                }).collect(Collectors.toList()));
            }
            msgTmpResVo.setCfgRuleConditionsList(getRuleConditionList(msgTmpResVo.getId()));

        }

        return msgTmpResVo;
    }

    private List<CfgRuleConditions> getRuleConditionList(String  msgId)
    {
        return cfgRuleConditionsService.getBaseMapper().selectList(
                new LambdaQueryWrapper<CfgRuleConditions>().eq(CfgRuleConditions::getMsgid,msgId));
    }


    private void insertRuleStepConditions(String usrId, String msgId, List<CfgRuleConditions> conditionList)
    {

        cfgRuleConditionsService.remove(new LambdaQueryWrapper<CfgRuleConditions>()
                .eq(CfgRuleConditions::getMsgid,msgId));
        if( conditionList == null || conditionList.size() == 0)
            return;
        for(CfgRuleConditions cfgRuleConditions : conditionList)
        {
            //addRuleCondition(usrId, ruleStepId, cfgRuleConditions);
            cfgRuleConditions.setMsgid(msgId);
            if(ObjectUtils.isNull(cfgRuleConditions.getVarId()))
                return;
            if(ObjectUtils.isNull(cfgRuleConditions.getOp()))
                return;

            CfgRuleVars cfgRuleVars = cfgRuleVarsService.getById(cfgRuleConditions.getVarId());
            if(cfgRuleVars.getFieldType().equals("date"))
                cfgRuleVars.setFieldType("string");
            String opSql = EnumRuleVarsOp.getOpSqlByCode(cfgRuleConditions.getOp(),cfgRuleVars,cfgRuleConditions.getOpVal());
            cfgRuleConditions.setConditionSql(opSql);
            cfgRuleConditions.setMsgid(msgId);
            cfgRuleConditions.setInputType(cfgRuleVars.getInputType());
            cfgRuleConditionsService.save(cfgRuleConditions);
        }
    }
    private String getStepConditionSql(String msgId,String sqlFormula)
    {
        List<CfgRuleConditions> cfgRuleConditionsList = cfgRuleConditionsService.getBaseMapper().selectList(
                new LambdaQueryWrapper<CfgRuleConditions>().eq(CfgRuleConditions::getMsgid,msgId));
        String retSql = sqlFormula;
        for(CfgRuleConditions cfgRuleConditions : cfgRuleConditionsList){
            retSql  = retSql.replace( cfgRuleConditions.getConditionCode(), cfgRuleConditions.getConditionSql());
        }
        return retSql;
    }
}




